<template>
  <div class="role-permission-root">
    <div v-if="previewMode" class="preview-bar">
      <span>当前为
        <select v-model="previewRoleId" @change="changePreviewRole(($event.target as HTMLSelectElement).value)" class="preview-role-select">
          <option v-for="role in roles" :key="role.id" :value="role.id">{{ role.name }}</option>
        </select>
        角色预览模式，仅显示该角色有权限的菜单和页面。
      </span>
      <button class="preview-exit-btn" @click="exitPreview">退出预览</button>
    </div>
    <div class="role-permission-container">
      <!-- 左侧菜单 -->
      <div class="role-sidebar">
        <div v-if="previewMode" class="preview-menu-list">
          <div v-for="menu in previewMenus" :key="menu.key" :class="['preview-menu-item', { active: menu.key === previewMenuKey }]" @click="selectPreviewMenu(menu.key)">{{ menu.title }}</div>
          <div v-if="!previewMenus.length" style="color:#aaa;padding:24px 0;text-align:center;">暂无可见菜单</div>
        </div>
        <div v-else class="role-sidebar-header">
          <span class="role-sidebar-title">角色管理</span>
          <button class="role-add-btn" @click="openEditDialog()">新增角色</button>
        </div>
        <div v-if="!previewMode" class="role-list">
          <div v-for="role in roles" :key="role.id" :class="['role-card', { active: role.id === currentRole.id }]" @click="selectRole(role)">
            <!-- 状态标签右上角 -->
            <span class="role-status-badge" :class="role.status === '启用' ? 'enabled' : 'disabled'">{{ role.status === '启用' ? '已启用' : '已禁用' }}</span>
            <div class="role-card-title">{{ role.name }}</div>
            <div class="role-card-desc">{{ role.desc }}</div>
            <div class="role-card-meta">
              <span class="role-member-link" @click.stop="openMemberDialog(role)">成员：{{ role.userCount }}人</span>
            </div>
            <!-- 操作按钮横向排列，悬浮于卡片下方 -->
            <div class="role-card-actions">
              <button class="role-delete-btn" @click.stop="confirmDeleteRole(role)">删除</button>
              <button class="role-edit-btn" @click.stop="openEditDialog(role)">编辑</button>
            </div>
          </div>
        </div>
      </div>
      <!-- 右侧主内容区 -->
      <div class="perm-main-panel">
        <div v-if="previewMode" class="preview-content">
          <template v-if="previewMenus.length && previewMenuKey">
            <template v-for="menu in previewMenus">
              <div v-if="menu.key === previewMenuKey" :key="menu.key" class="preview-page-mock">
                <div class="preview-page-title">{{ menu.title }}</div>
                <div class="preview-page-desc">（页面内容仅做预览，实际内容需按权限点开发）</div>
                <div v-if="Array.isArray(menu.pagePerms) && menu.pagePerms.length" class="preview-page-btns">
                  <template v-for="btn in menu.pagePerms">
                    <el-button
                      v-if="btn && typeof btn === 'object' && btn.perm && btn.label && btn.key && previewPerms && previewPerms.includes(btn.perm)"
                      :key="btn.key"
                      type="primary"
                      size="small"
                      style="margin-right:12px;"
                    >{{ btn.label }}</el-button>
                  </template>
                </div>
                <div v-if="Array.isArray(menu.pagePerms) && !previewHasPageBtnPerm(menu) && menu.pagePerms.length"
                     style="color:#aaa;margin-top:18px;">无可用操作权限</div>
              </div>
            </template>
          </template>
          <div v-else style="color:#aaa;padding:48px 0;text-align:center;">暂无可见页面</div>
        </div>
        <div v-else class="perm-header">
          <div class="perm-title">权限配置 <span class="perm-role-tag">{{ currentRole.name }}</span></div>
          <div class="perm-actions">
            <select v-model="selectedTemplate" class="perm-template-select" @change="applyTemplate">
              <option value="">选择权限模板</option>
              <option v-for="tpl in permTemplates" :key="tpl.name" :value="tpl.name">{{ tpl.name }}</option>
            </select>
            <button class="perm-btn perm-reset" @click="resetPerms">重置</button>
            <button class="perm-btn perm-save" :disabled="saving" @click="savePerms">
              <span v-if="saving" class="perm-btn-loading"></span>
              保存配置
            </button>
            <button class="perm-btn perm-save" @click="saveAsTemplate">保存为模板</button>
            <button class="perm-btn perm-log" @click="openLogDialog">变更日志</button>
            <button class="perm-btn perm-preview" @click="enterPreview">预览</button>
            <button class="perm-btn perm-template-manage" @click="openTemplateManageDialog">管理模板</button>
          </div>
        </div>
        <div v-if="!previewMode" class="perm-content">
          <div v-for="module in permModules" :key="module.key" class="perm-module">
            <div class="perm-module-title">{{ module.title }}</div>
            <div v-for="page in module.pages" :key="page.key" class="perm-page">
              <div class="perm-page-title">
                {{ page.title }}
                <button class="perm-page-batch" @click="selectAllPage(page, true)">全选</button>
                <button class="perm-page-batch" @click="selectAllPage(page, false)">反选</button>
              </div>
              <div class="perm-op-list">
                <div v-for="perm in page.perms" :key="perm.key" class="perm-op-card">
                  <div class="perm-op-main">
                    <div class="perm-op-label" :title="perm.desc">{{ perm.title }}</div>
                    <label class="perm-switch">
                      <input type="checkbox"
                        :checked="isPermChecked(page.key, perm.key)"
                        :disabled="perm.key !== 'view' && !isPermChecked(page.key, 'view')"
                        @change="e => onPermChange(page.key, perm.key, (e.target as HTMLInputElement)?.checked)"
                      >
                      <span class="perm-slider"></span>
                    </label>
                  </div>
                  <div class="perm-op-desc">{{ perm.desc }}</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <el-dialog v-model="editDialogVisible" :title="editMode === 'add' ? '新增角色' : '编辑角色'" width="400px" :close-on-click-modal="false">
        <div class="edit-form">
          <label>角色名称</label>
          <input v-model="editForm.name" placeholder="请输入角色名称" class="edit-input" />
          <label>角色描述</label>
          <textarea v-model="editForm.desc" placeholder="请输入角色描述" class="edit-input"></textarea>
          <label>状态</label>
          <select v-model="editForm.status" class="edit-input">
            <option value="启用">启用</option>
            <option value="禁用">禁用</option>
          </select>
        </div>
        <template #footer>
          <button class="perm-btn perm-reset" @click="editDialogVisible = false">取消</button>
          <button class="perm-btn perm-save" @click="saveEditRole">保存</button>
        </template>
      </el-dialog>
      <!-- 角色删除弹窗 -->
      <el-dialog v-model="deleteDialogVisible" title="删除角色" width="340px" :close-on-click-modal="false">
        <div style="margin:18px 0;">确定要删除角色 <b>{{ roleToDelete?.name }}</b> 吗？</div>
        <template #footer>
          <button class="perm-btn perm-reset" @click="deleteDialogVisible = false">取消</button>
          <button class="perm-btn perm-save" @click="doDeleteRole">删除</button>
        </template>
      </el-dialog>
      <!-- 成员管理弹窗 -->
      <el-dialog v-model="memberDialogVisible" :title="memberRoleName + '成员列表'" width="340px" :close-on-click-modal="false">
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
          <span>成员名单</span>
          <el-button size="small" type="primary" @click="openSelectDialog">添加成员</el-button>
        </div>
        <ul style="margin:18px 0;">
          <li v-for="m in memberList" :key="m.id" style="display: flex; align-items: center; justify-content: space-between;">
            <span>{{ m.name }}</span>
            <el-button size="mini" type="danger" @click="removeMember(m)">移除</el-button>
          </li>
          <li v-if="!memberList.length" style="color:#aaa;">暂无成员</li>
        </ul>
        <template #footer>
          <button class="perm-btn perm-save" @click="memberDialogVisible = false">关闭</button>
        </template>
      </el-dialog>
      <!-- 选择员工弹窗 -->
      <el-dialog v-model="selectDialogVisible" title="选择员工" width="340px" :close-on-click-modal="false">
        <el-checkbox-group v-model="selectedEmployees">
          <el-checkbox v-for="e in allEmployees" :key="e.id" :label="e.id" :disabled="memberList.some((m: any) => m.id === e.id)">{{ e.name }}</el-checkbox>
        </el-checkbox-group>
        <template #footer>
          <button class="perm-btn perm-reset" @click="selectDialogVisible = false">取消</button>
          <button class="perm-btn perm-save" @click="confirmAddMembers">确定</button>
        </template>
      </el-dialog>
      <!-- 权限变更日志弹窗（布局优化） -->
      <el-dialog v-model="logDialogVisible" title="权限变更日志" width="600px" :close-on-click-modal="false">
        <el-table :data="permLogs" size="small" border style="width:100%;font-size:13px;">
          <el-table-column prop="time" label="时间" width="140" align="center" />
          <el-table-column prop="user" label="操作人" width="80" align="center" />
          <el-table-column prop="role" label="角色" width="100" align="center" />
          <el-table-column prop="detail" label="变更详情" min-width="220" show-overflow-tooltip />
        </el-table>
        <div v-if="!permLogs.length" style="color:#aaa;text-align:center;padding:32px 0;">暂无变更记录</div>
        <template #footer>
          <button class="perm-btn perm-save" @click="logDialogVisible = false">关闭</button>
        </template>
      </el-dialog>
      <!-- 模板管理弹窗 -->
      <el-dialog v-model="templateManageDialogVisible" title="权限模板管理" width="480px" :close-on-click-modal="false">
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
          <span>模板列表</span>
          <label style="font-size:14px;cursor:pointer;">
            <input type="file" accept=".json" style="display:none" @change="importTemplate" />
            <span class="perm-btn perm-template-import">导入模板</span>
          </label>
        </div>
        <el-table :data="permTemplates" size="small" border style="width:100%">
          <el-table-column prop="name" label="模板名称" />
          <el-table-column label="操作" width="220">
            <template #default="scope">
              <el-button size="mini" @click="openTemplateRenameDialog(scope.row)">重命名</el-button>
              <el-button size="mini" @click="previewTemplatePerms(scope.row)">预览</el-button>
              <el-button size="mini" @click="() => exportTemplate(scope.row)">导出</el-button>
              <el-button size="mini" type="danger" @click="() => deleteTemplate(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <div v-if="!permTemplates.length" style="color:#aaa;text-align:center;padding:32px 0;">暂无模板</div>
        <template #footer>
          <button class="perm-btn perm-save" @click="templateManageDialogVisible = false">关闭</button>
        </template>
      </el-dialog>
      <!-- 模板重命名弹窗 -->
      <el-dialog v-if="templateRenameDialogVisible" v-model="templateRenameDialogVisible" title="重命名模板" width="320px" :close-on-click-modal="false" @close="closeRenameDialog">
        <div style="margin:18px 0;">
          <input v-model="templateRenameInput" placeholder="请输入新模板名称" style="width:100%;padding:8px;font-size:15px;" />
        </div>
        <template #footer>
          <button class="perm-btn perm-reset" @click="closeRenameDialog">取消</button>
          <button class="perm-btn perm-save" @click="confirmRenameTemplate">确定</button>
        </template>
      </el-dialog>
      <!-- 模板预览弹窗 -->
      <el-dialog v-model="templatePreviewDialogVisible" title="模板权限点预览" width="420px" :close-on-click-modal="false">
        <div style="max-height:320px;overflow:auto;">
          <ul>
            <li v-for="p in templatePreviewPerms" :key="p" style="margin-bottom:6px;">{{ p }}</li>
          </ul>
        </div>
        <template #footer>
          <button class="perm-btn perm-save" @click="templatePreviewDialogVisible = false">关闭</button>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import permModules from '@/permissions/perm-structure'
// 角色数据 mock
const roles = ref([
  { id: '1', name: '超级管理员', desc: '拥有系统所有权限', status: '启用', userCount: 2, users: ['张三', '李四'] },
  { id: '2', name: '商品管理员', desc: '负责商品上下架和管理', status: '启用', userCount: 8, users: ['王五', '赵六', '小明', '小红', '小刚', '小美', '小李', '小赵'] },
  { id: '3', name: '订单管理员', desc: '负责处理订单和售后', status: '启用', userCount: 12, users: ['订单1', '订单2', '订单3', '订单4', '订单5', '订单6', '订单7', '订单8', '订单9', '订单10', '订单11', '订单12'] },
  { id: '4', name: '客服主管', desc: '管理客服团队和客户反馈', status: '禁用', userCount: 5, users: ['客服A', '客服B', '客服C', '客服D', '客服E'] },
])
const currentRole = ref(roles.value[0])
function selectRole(role: any) {
  currentRole.value = role
  currentPerms.value = rolePerms[role.id] ? [...rolePerms[role.id]] : []
}
// 权限模块 mock
const rolePerms: Record<string, string[]> = {
  '1': [
    'product.list.view', 'product.list.add', 'product.list.edit', 'product.list.delete', 'product.list.toggle',
    'product.category.add', 'product.category.edit',
  ],
  '2': ['product.list.view', 'product.list.add', 'product.list.edit', 'product.list.toggle', 'product.category.add', 'product.category.edit'],
  '3': ['product.list.view', 'product.list.add'],
  '4': []
}
const currentPerms = ref<string[]>(rolePerms[currentRole.value.id] ? [...rolePerms[currentRole.value.id]] : [])
function isPermChecked(pageKey: string, permKey: string) {
  return currentPerms.value.includes(pageKey + '.' + permKey)
}
function onPermChange(pageKey: string, permKey: string, checked: boolean) {
  const perm = pageKey + '.' + permKey
  if (checked) {
    if (permKey !== 'view' && !isPermChecked(pageKey, 'view')) {
      currentPerms.value.push(pageKey + '.view')
    }
    if (!currentPerms.value.includes(perm)) currentPerms.value.push(perm)
  } else {
    if (permKey === 'view') {
      currentPerms.value = currentPerms.value.filter(k => !k.startsWith(pageKey + '.'))
    } else {
      currentPerms.value = currentPerms.value.filter(k => k !== perm)
    }
  }
}
function resetPerms() {
  currentPerms.value = rolePerms[currentRole.value.id] ? [...rolePerms[currentRole.value.id]] : []
}
// 保存 loading
const saving = ref(false)
// mock 当前操作人
const currentUser = '管理员A'
// 权限变更日志结构
interface PermLog {
  time: string
  user: string
  role: string
  detail: string
}
const permLogs = ref<PermLog[]>([])
const logDialogVisible = ref(false)
function openLogDialog() {
  logDialogVisible.value = true
}
// 保存权限配置时记录日志（仅有变化时记录）
function savePerms() {
  saving.value = true
  setTimeout(() => {
    // 记录变更日志
    const oldPerms = rolePerms[currentRole.value.id] ? [...rolePerms[currentRole.value.id]] : []
    const newPerms = [...currentPerms.value]
    const added = newPerms.filter(p => !oldPerms.includes(p))
    const removed = oldPerms.filter(p => !newPerms.includes(p))
    let detail = ''
    if (added.length) detail += `增加：${added.join('，')}`
    if (removed.length) detail += (detail ? '；' : '') + `移除：${removed.join('，')}`
    if (detail) {
      permLogs.value.unshift({
        time: new Date().toLocaleString(),
        user: currentUser,
        role: currentRole.value.name,
        detail
      })
    }
    rolePerms[currentRole.value.id] = [...currentPerms.value]
    saving.value = false
    alert('权限配置已保存！')
  }, 1200)
}
// 页面级全选/反选
function selectAllPage(page: any, flag: boolean) {
  page.perms.forEach((perm: any) => {
    onPermChange(page.key, perm.key, flag)
  })
}
// 角色编辑弹窗
const editDialogVisible = ref(false)
const editMode = ref<'add'|'edit'>('add')
const editForm = ref({ id: '', name: '', desc: '', status: '启用', userCount: 0, users: [] as string[] })
function openEditDialog(role?: any) {
  if (role) {
    editMode.value = 'edit'
    editForm.value = { ...role, users: role.users || [] }
  } else {
    editMode.value = 'add'
    editForm.value = { id: '', name: '', desc: '', status: '启用', userCount: 0, users: [] }
  }
  editDialogVisible.value = true
}
function saveEditRole() {
  if (!editForm.value.name) return alert('请输入角色名称')
  if (editMode.value === 'add') {
    const newId = (Math.random() * 100000).toFixed(0)
    roles.value.push({ ...editForm.value, id: newId, users: editForm.value.users || [] })
  } else {
    const idx = roles.value.findIndex(r => r.id === editForm.value.id)
    if (idx > -1) roles.value[idx] = { ...editForm.value, users: editForm.value.users || [] }
  }
  editDialogVisible.value = false
}
// 角色删除弹窗
const deleteDialogVisible = ref(false)
const roleToDelete = ref<any>(null)
function confirmDeleteRole(role: any) {
  roleToDelete.value = role
  deleteDialogVisible.value = true
}
function doDeleteRole() {
  const idx = roles.value.findIndex(r => r.id === roleToDelete.value.id)
  if (idx > -1) {
    roles.value.splice(idx, 1)
    // 自动切换到下一个角色
    if (roles.value.length) {
      currentRole.value = roles.value[Math.max(0, idx - 1)]
      currentPerms.value = rolePerms[currentRole.value.id] ? [...rolePerms[currentRole.value.id]] : []
    }
  }
  deleteDialogVisible.value = false
}
// 成员管理弹窗
const memberDialogVisible = ref(false)
const memberList = ref<any[]>([])
const memberRoleName = ref('')
// mock 员工库
const allEmployees = [
  { id: 1, name: '张三' },
  { id: 2, name: '李四' },
  { id: 3, name: '王五' },
  { id: 4, name: '赵六' },
  { id: 5, name: '小明' },
  { id: 6, name: '小红' },
  { id: 7, name: '小刚' },
  { id: 8, name: '小美' },
  { id: 9, name: '小李' },
  { id: 10, name: '小赵' },
  { id: 11, name: '订单1' },
  { id: 12, name: '订单2' },
  { id: 13, name: '订单3' },
  { id: 14, name: '订单4' },
  { id: 15, name: '客服A' },
  { id: 16, name: '客服B' },
  { id: 17, name: '客服C' },
  { id: 18, name: '客服D' },
  { id: 19, name: '客服E' },
]

// 选择员工弹窗
const selectDialogVisible = ref(false)
const selectedEmployees = ref<number[]>([])
function openSelectDialog() {
  selectedEmployees.value = []
  selectDialogVisible.value = true
}
function confirmAddMembers() {
  // 只添加未在当前成员中的员工
  const toAdd = allEmployees.filter(e => selectedEmployees.value.includes(e.id) && !memberList.value.some((m: any) => m.id === e.id))
  memberList.value.push(...toAdd)
  // 同步到角色数据
  const role = roles.value.find(r => r.name === memberRoleName.value)
  if (role) {
    role.users = memberList.value.map((m: any) => m)
    role.userCount = memberList.value.length
  }
  selectDialogVisible.value = false
}
function removeMember(member: any) {
  memberList.value = memberList.value.filter((m: any) => m.id !== member.id)
  // 同步到角色数据
  const role = roles.value.find(r => r.name === memberRoleName.value)
  if (role) {
    role.users = memberList.value.map((m: any) => m)
    role.userCount = memberList.value.length
  }
}
// 修改 openMemberDialog 以适配新结构
function openMemberDialog(role: any) {
  memberList.value = (role.users && role.users.length && typeof role.users[0] === 'object') ? [...role.users] : (role.users ? role.users.map((n: string, i: number) => ({ id: 1000 + i, name: n })) : [])
  memberRoleName.value = role.name
  memberDialogVisible.value = true
}
// 权限模板
const permTemplates = ref([
  {
    name: '全功能模板',
    perms: [
      'product.list.view', 'product.list.add', 'product.list.edit', 'product.list.delete', 'product.list.toggle',
      'product.category.add', 'product.category.edit',
      'product.recommend.view', 'product.recommend.add', 'product.recommend.edit', 'product.recommend.delete', 'product.recommend.enable',
      'order.list.view', 'order.list.edit', 'order.list.delete', 'order.list.export',
      'member.list.view', 'member.list.edit', 'member.list.delete', 'member.list.export',
      'service.list.view', 'service.list.reply', 'service.list.close',
      'dashboard.view', 'settings.view', 'settings.edit',
    ]
  },
  {
    name: '只读模板',
    perms: [
      'product.list.view',
      'product.recommend.view',
      'order.list.view',
      'member.list.view',
      'service.list.view',
      'dashboard.view',
      'settings.view',
    ]
  },
  {
    name: '商品专员',
    perms: [
      'product.list.view', 'product.list.add', 'product.list.edit', 'product.list.delete', 'product.list.toggle',
      'product.category.add', 'product.category.edit',
      'product.recommend.view', 'product.recommend.add', 'product.recommend.edit', 'product.recommend.enable'
    ]
  },
  {
    name: '订单专员',
    perms: [
      'order.list.view', 'order.list.edit', 'order.list.delete', 'order.list.export'
    ]
  },
  {
    name: '客服专员',
    perms: [
      'service.list.view', 'service.list.reply', 'service.list.close'
    ]
  }
])
const selectedTemplate = ref('')
function applyTemplate() {
  const tpl = permTemplates.value.find(t => t.name === selectedTemplate.value)
  if (tpl) currentPerms.value = [...tpl.perms]
}
function saveAsTemplate() {
  const name = prompt('请输入模板名称')
  if (name) permTemplates.value.push({ name, perms: [...currentPerms.value] })
}
// mock 菜单结构
const allMenus = [
  { key: 'dashboard', title: '首页', perm: 'dashboard.view', pagePerms: [] as { key: string; label: string; perm: string }[] },
  { key: 'product', title: '商品管理', perm: 'product.list.view', pagePerms: [
    { key: 'add', label: '新增商品', perm: 'product.list.add' },
    { key: 'edit', label: '编辑商品', perm: 'product.list.edit' },
    { key: 'delete', label: '删除商品', perm: 'product.list.delete' },
    { key: 'export', label: '导出商品', perm: 'product.list.export' },
  ] },
  { key: 'order', title: '订单管理', perm: 'order.list.view', pagePerms: [
    { key: 'edit', label: '编辑订单', perm: 'order.list.edit' },
    { key: 'delete', label: '删除订单', perm: 'order.list.delete' },
    { key: 'export', label: '导出订单', perm: 'order.list.export' },
  ] },
  { key: 'member', title: '会员管理', perm: 'member.list.view', pagePerms: [
    { key: 'edit', label: '编辑会员', perm: 'member.list.edit' },
    { key: 'delete', label: '删除会员', perm: 'member.list.delete' },
    { key: 'export', label: '导出会员', perm: 'member.list.export' },
  ] },
  { key: 'service', title: '客服中心', perm: 'service.list.view', pagePerms: [] as { key: string; label: string; perm: string }[] },
  { key: 'settings', title: '基础设置', perm: 'settings.view', pagePerms: [] as { key: string; label: string; perm: string }[] },
]
const previewMode = ref(false)
const previewRoleId = ref('')
const previewRole = computed(() => roles.value.find(r => r.id === previewRoleId.value) || currentRole.value)
const previewPerms = computed(() => rolePerms[previewRole.value.id] ? [...rolePerms[previewRole.value.id]] : [])
const previewMenus = computed(() => {
  if (!previewMode.value) return allMenus
  return allMenus.filter(menu => previewPerms.value.includes(menu.perm))
})
const previewMenuKey = ref('')
function enterPreview() {
  previewMode.value = true
  previewRoleId.value = currentRole.value.id
  // 默认选中第一个有权限的菜单
  const firstMenu = allMenus.find(menu => rolePerms[currentRole.value.id]?.includes(menu.perm))
  previewMenuKey.value = firstMenu ? firstMenu.key : ''
}
function exitPreview() {
  previewMode.value = false
  previewMenuKey.value = ''
}
function selectPreviewMenu(key: string) {
  previewMenuKey.value = key
}
function changePreviewRole(id: string) {
  previewRoleId.value = id
  // 切换角色后自动选中第一个有权限的菜单
  const firstMenu = allMenus.find(menu => rolePerms[id]?.includes(menu.perm))
  previewMenuKey.value = firstMenu ? firstMenu.key : ''
}
function previewHasPageBtnPerm(menu: any) {
  if (!Array.isArray(menu.pagePerms) || !previewPerms.value) return false
  return menu.pagePerms.some((btn: any) => previewPerms.value.includes(btn.perm))
}
// 模板管理弹窗相关
const templateManageDialogVisible = ref(false)
const templateToEdit = ref<any>(null)
const templateRenameInput = ref('')
const templatePreviewDialogVisible = ref(false)
const templatePreviewPerms = ref<string[]>([])
function openTemplateManageDialog() {
  templateManageDialogVisible.value = true
}
function openTemplateRenameDialog(tpl: any) {
  templateToEdit.value = tpl
  templateRenameInput.value = tpl.name
  templateRenameDialogVisible.value = true
}
function closeRenameDialog() {
  templateRenameDialogVisible.value = false
  templateToEdit.value = null
  templateRenameInput.value = ''
}
function confirmRenameTemplate() {
  if (templateToEdit.value && templateRenameInput.value) {
    templateToEdit.value.name = templateRenameInput.value
    closeRenameDialog()
  }
}
function deleteTemplate(tpl: any) {
  const idx = permTemplates.value.findIndex(t => t === tpl)
  if (idx > -1) permTemplates.value.splice(idx, 1)
}
function previewTemplatePerms(tpl: any) {
  templatePreviewPerms.value = tpl.perms
  templatePreviewDialogVisible.value = true
}
function exportTemplate(tpl: any) {
  const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(tpl, null, 2))
  const dl = document.createElement('a')
  dl.setAttribute('href', dataStr)
  dl.setAttribute('download', tpl.name + '.json')
  dl.click()
}
function importTemplate(e: Event) {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (!file) return
  const reader = new FileReader()
  reader.onload = function(evt) {
    try {
      const tpl = JSON.parse(evt.target?.result as string)
      if (tpl && tpl.name && Array.isArray(tpl.perms)) {
        permTemplates.value.push(tpl)
      } else {
        alert('模板格式不正确')
      }
    } catch {
      alert('模板解析失败')
    }
  }
  reader.readAsText(file)
}
</script>

<style scoped>
.role-permission-root {
  min-height: 100vh;
  background: #f7f8fa;
  padding: 32px 0;
}
.role-permission-container {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 4px 32px rgba(67,97,238,0.08);
  overflow: hidden;
}
.role-sidebar {
  width: 320px;
  background: #f8f9fb;
  border-right: 1.5px solid #f0f1f5;
  padding: 32px 0 32px 0;
  display: flex;
  flex-direction: column;
}
.role-sidebar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 32px 18px 32px;
  border-bottom: 1px solid #ececec;
  margin-bottom: 18px;
}
.role-sidebar-title {
  font-size: 20px;
  font-weight: 600;
  color: #222;
}
.role-add-btn {
  background: #4361ee;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 7px 18px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
}
.role-add-btn:hover {
  background: #3f37c9;
}
.role-list {
  flex: 1;
  overflow-y: auto;
  padding: 0 16px 0 16px;
}
.role-card {
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 2px 8px rgba(67,97,238,0.04);
  border: 2px solid transparent;
  margin-bottom: 24px;
  padding: 24px 24px 44px 24px;
  cursor: pointer;
  position: relative;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.role-card.active {
  border-color: #4361ee;
  box-shadow: 0 4px 16px rgba(67,97,238,0.10);
}
.role-card-title {
  font-size: 20px;
  font-weight: 700;
  color: #222;
  margin-bottom: 6px;
}
.role-card-desc {
  font-size: 15px;
  color: #888;
  margin-bottom: 10px;
}
.role-card-meta {
  display: flex;
  align-items: center;
  font-size: 14px;
  margin-bottom: 8px;
}
.role-member-link {
  color: #4361ee;
  cursor: pointer;
  text-decoration: underline;
  font-weight: 500;
}
.role-status-badge {
  position: absolute;
  top: 18px;
  right: 24px;
  padding: 3px 18px;
  border-radius: 16px;
  font-size: 15px;
  font-weight: 500;
  z-index: 2;
}
.role-status-badge.enabled {
  background: #e6f7ff;
  color: #3bbdff;
}
.role-status-badge.disabled {
  background: #ffe6f0;
  color: #f72585;
}
.role-card-actions {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 12px;
  display: flex;
  justify-content: flex-start;
  gap: 12px;
  z-index: 3;
}
.role-delete-btn {
  background: #ffe6f0;
  color: #f72585;
  border: none;
  border-radius: 10px;
  padding: 4px 24px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
  box-shadow: 0 2px 8px rgba(247,37,133,0.06);
}
.role-delete-btn:hover {
  background: #ffd6e0;
}
.role-edit-btn {
  background: #f5f6fa;
  color: #4361ee;
  border: none;
  border-radius: 10px;
  padding: 4px 24px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
  box-shadow: 0 2px 8px rgba(67,97,238,0.06);
}
.role-edit-btn:hover {
  background: #e9eaf0;
}
.perm-main-panel {
  flex: 1;
  padding: 38px 48px 38px 48px;
  overflow-y: auto;
}
.perm-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 28px;
}
.perm-title {
  font-size: 22px;
  font-weight: 700;
  color: #222;
}
.perm-role-tag {
  background: #f0f4ff;
  color: #4361ee;
  border-radius: 8px;
  padding: 3px 16px;
  font-size: 15px;
  font-weight: 500;
  margin-left: 12px;
}
.perm-actions {
  display: flex;
  gap: 16px;
}
.perm-btn {
  border: none;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 500;
  padding: 7px 22px;
  cursor: pointer;
  transition: background 0.2s;
}
.perm-reset {
  background: #f5f6fa;
  color: #222;
}
.perm-reset:hover {
  background: #e9eaf0;
}
.perm-save {
  background: #4361ee;
  color: #fff;
}
.perm-save:hover {
  background: #3f37c9;
}
.perm-log {
  background: #f5f6fa;
  color: #4361ee;
  border: none;
  border-radius: 10px;
  padding: 4px 24px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
  box-shadow: 0 2px 8px rgba(67,97,238,0.06);
}
.perm-log:hover {
  background: #e9eaf0;
}
.perm-content {
  margin-top: 8px;
}
.perm-module {
  margin-bottom: 36px;
}
.perm-module-title {
  font-size: 18px;
  font-weight: 600;
  color: #222;
  margin-bottom: 18px;
  border-bottom: 1px dashed #e0e0e0;
  padding-bottom: 8px;
}
.perm-page {
  margin-bottom: 18px;
}
.perm-page-title {
  font-size: 16px;
  font-weight: 500;
  color: #222;
  margin-bottom: 10px;
}
.perm-op-list {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 24px;
}
.perm-op-card {
  background: #f8f9fb;
  border-radius: 12px;
  padding: 18px 22px 12px 22px;
  min-width: 260px;
  max-width: 320px;
  flex: 1 1 260px;
  box-shadow: 0 1px 4px rgba(67,97,238,0.04);
  margin-bottom: 8px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.perm-op-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.perm-op-label {
  font-size: 15px;
  font-weight: 600;
  color: #222;
}
.perm-switch {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 24px;
}
.perm-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.perm-slider {
  position: absolute;
  cursor: pointer;
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: #e0e0e0;
  transition: .4s;
  border-radius: 24px;
}
.perm-switch input:checked + .perm-slider {
  background-color: #4361ee;
}
.perm-slider:before {
  position: absolute;
  content: "";
  height: 18px;
  width: 18px;
  left: 3px;
  bottom: 3px;
  background-color: #fff;
  transition: .4s;
  border-radius: 50%;
}
.perm-switch input:checked + .perm-slider:before {
  transform: translateX(20px);
}
.perm-op-desc {
  font-size: 13px;
  color: #888;
  margin-left: 2px;
}
.perm-page-batch {
  margin-left: 12px;
  background: #f5f6fa;
  color: #4361ee;
  border: none;
  border-radius: 6px;
  padding: 2px 12px;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.2s;
}
.perm-page-batch:hover {
  background: #e9eaf0;
}
.perm-btn-loading {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid #fff;
  border-top: 2px solid #4361ee;
  border-radius: 50%;
  margin-right: 6px;
  animation: spin 0.8s linear infinite;
  vertical-align: middle;
}
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.edit-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 18px 0;
}
.edit-input {
  border: 1px solid #e0e6f7;
  border-radius: 6px;
  padding: 8px;
  font-size: 15px;
}
.perm-template-select {
  border: 1px solid #e0e6f7;
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 15px;
  margin-right: 12px;
}
.el-dialog__body {
  padding-top: 18px !important;
  padding-bottom: 8px !important;
}
.el-table th, .el-table td {
  padding: 6px 8px !important;
  font-size: 13px !important;
}
.preview-bar {
  background: #f0f4ff;
  color: #4361ee;
  padding: 12px 32px;
  font-size: 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.preview-exit-btn {
  background: #ffe6f0;
  color: #f72585;
  border: none;
  border-radius: 8px;
  padding: 6px 18px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  margin-left: 24px;
}
.preview-menu-list {
  padding: 32px 0 0 0;
}
.preview-menu-item {
  font-size: 17px;
  color: #222;
  padding: 12px 32px;
  border-radius: 8px;
  margin-bottom: 10px;
  background: #f7f8fa;
  font-weight: 500;
}
.preview-menu-item.active {
  background: #4361ee;
  color: #fff;
}
.preview-role-select {
  margin: 0 8px;
  padding: 2px 8px;
  border-radius: 6px;
  border: 1px solid #d0d4e0;
  font-size: 15px;
}
.preview-page-btns {
  margin-top: 18px;
}
.preview-content {
  padding: 48px 24px;
}
.preview-page-mock {
  background: #f8f9fb;
  border-radius: 12px;
  margin-bottom: 24px;
  padding: 32px 24px 24px 24px;
  box-shadow: 0 2px 8px rgba(67,97,238,0.04);
}
.preview-page-title {
  font-size: 20px;
  font-weight: 700;
  color: #222;
  margin-bottom: 8px;
}
.preview-page-desc {
  font-size: 15px;
  color: #888;
}
.perm-btn.perm-preview {
  background: #f0f4ff;
  color: #4361ee;
  border: none;
  border-radius: 10px;
  padding: 4px 24px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
  box-shadow: 0 2px 8px rgba(67,97,238,0.06);
}
.perm-btn.perm-preview:hover {
  background: #e0e8ff;
}
.perm-btn.perm-template-manage {
  background: #f5f6fa;
  color: #4361ee;
  border: none;
  border-radius: 10px;
  padding: 4px 18px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  margin-left: 8px;
}
.perm-btn.perm-template-manage:hover {
  background: #e9eaf0;
}
.perm-btn.perm-template-import {
  background: #f0f4ff;
  color: #4361ee;
  border-radius: 8px;
  padding: 4px 14px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  margin-left: 8px;
  display: inline-block;
}
.perm-btn.perm-template-import:hover {
  background: #e0e8ff;
}
</style>  